﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using WCell.RealmServer.Skills;
using WCell.RealmServer.Spells;
using WCell.RealmServer.Talents;
using WCell.Tools.Code;
using WCell.Util;
using WCell.Constants;
using WCell.Constants.Spells;
using WCell.Tools.Domi;
using WCell.Util.Toolshed;
using NLog;

namespace WCell.Tools.Spells
{
	public class SpellLineWriter
	{
		private static readonly Logger log = LogManager.GetCurrentClassLogger();

		private static CodeFileWriter writer;
		public static Dictionary<string, List<Spell>>[] Maps
		{
			get;
			private set;
		}

		[Tool]
		public static void WriteSpellLines()
		{
			WriteSpellLines(ToolConfig.RealmServerRoot + "Spells/SpellLines.Def.cs");
		}

		public static void WriteSpellLines(string outputFileName)
		{
			CreateMaps();
			WCellEnumWriter.WriteSpellLinesEnum();

			using (writer = new CodeFileWriter(outputFileName, "WCell.RealmServer.Spells", "SpellLines", "static partial class", "",
				"WCell.Constants.Spells"))
			{
				writer.WriteMethod("private", "static void", "SetupSpellLines", "", WriteSpellLinesMethod);
			}
		}

		private static void WriteSpellLinesMethod()
		{
			writer.WriteLine("SpellLine[] lines;");
			writer.WriteLine();
			for (var i = 0; i < Maps.Length; i++)
			{
				var map = Maps[i];
				var clss = (ClassId)i;

				if (map != null)
				{
					var listCount = map.Count;
					var s = 0;

					writer.WriteRegion(clss + " (" + listCount + ")");
					writer.WriteLine("lines = new SpellLine[]");
					writer.OpenBracket();
					foreach (var list in map.Values)
					{
						var lineName = SpellLine.GetSpellLineName(list.First());
						writer.WriteLine("new SpellLine(SpellLineId." + lineName + ", ");
						writer.IndentLevel++;
						for (var j = 0; j < list.Count; j++)
						{
							var spell = list[j];
							writer.WriteIndent("SpellHandler.Get(SpellId." + spell.SpellId + ")");
							if (j < list.Count - 1)
							{
								writer.WriteLine(",");
							}
						}
						writer.IndentLevel--;
						writer.Write(")");
						if (s < listCount - 1)
						{
							writer.WriteLine(",");
						}
						++s;
					}
					writer.CloseBracket(true);
					writer.WriteLine("AddSpellLines(lines);");
					writer.WriteEndRegion();
					writer.WriteLine();
				}
			}
		}

		public static void CreateMaps()
		{
			if (Maps != null)
			{
				return;
			}

			SpellHandler.LoadSpells();
			SkillHandler.Initialize();
			TalentMgr.Initialize();
			SpellHandler.Initialize2();

			Maps = new Dictionary<string, List<Spell>>[(int)ClassId.End];
			foreach (var spell in SpellHandler.ById)
			{
				if (spell == null)
				{
					continue;
				}

				if (spell.Skill == null || spell.IsTriggeredSpell)
				{
					continue;
				}

				var clss = spell.SpellClassSet.ToClassId();
				if (clss != 0 && (spell.Ability.ClassMask == 0 || spell.Ability.ClassMask.Has(clss)))
				{
					if (spell.SpellId.ToString().Contains("_"))
					{
						log.Warn("Duplicate: " + spell);
						continue;
					}
					var map = Maps[(int)clss];
					if (map == null)
					{
						Maps[(int)clss] = map = new Dictionary<string, List<Spell>>(100);
					}

					var name = spell.Name;
					if (!string.IsNullOrEmpty(spell.RankDesc) && !spell.RankDesc.Contains("Rank"))
					{
						name += " " + spell.RankDesc;
					}
					var line = map.GetOrCreate(name);
					line.Add(spell);
				}
			}

			foreach (var map in Maps)
			{
				if (map == null)
				{
					continue;
				}
				foreach (var list in map.Values)
				{
					list.Sort((a, b) => a.Rank.CompareTo(b.Rank));
				}
			}
		}


	}
}